# utils/ui_helpers.py
import customtkinter as ctk
import re


def create_scrollable_checkboxes(parent, categories, var_dict, platform_ctype_key, main_gui_ref):
    """
    创建带滚动条的复选框区域，并绑定鼠标滚轮（仅在悬停时生效）
    """
    canvas = ctk.CTkCanvas(parent, bg="#f5f5f5", highlightthickness=0)
    scrollbar = ctk.CTkScrollbar(parent, orientation="vertical", command=canvas.yview)
    scrollable_frame = ctk.CTkFrame(canvas, fg_color="#f5f5f5")

    scrollable_frame.bind(
        "<Configure>",
        lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
    )
    canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
    canvas.configure(yscrollcommand=scrollbar.set)

    for cat in categories:
        var = ctk.BooleanVar(value=False)
        var_dict.setdefault(platform_ctype_key, {})[cat] = var
        chk = ctk.CTkCheckBox(
            scrollable_frame,
            text=cat,
            variable=var,
            font=("Microsoft YaHei", 11),
            checkbox_width=18,
            checkbox_height=18
        )
        chk.pack(anchor="w", padx=15, pady=2)

    def _on_mousewheel(event):
        # Windows 滚轮单位为 120 的倍数；macOS/Linux 可能需额外处理，此处以 Windows 为主
        canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")

    def _bind_wheel(_event):
        canvas.bind_all("<MouseWheel>", _on_mousewheel)

    def _unbind_wheel(_event):
        canvas.unbind_all("<MouseWheel>")

    # 绑定进入/离开事件，实现“鼠标悬停时才响应滚轮”
    canvas.bind("<Enter>", _bind_wheel)
    canvas.bind("<Leave>", _unbind_wheel)
    scrollable_frame.bind("<Enter>", _bind_wheel)
    scrollable_frame.bind("<Leave>", _unbind_wheel)

    # 确保销毁时解绑全局事件，防止内存泄漏或重复绑定
    parent.bind("<Destroy>", lambda e: canvas.unbind_all("<MouseWheel>"))

    canvas.pack(side="left", fill="both", expand=True, padx=(10, 0), pady=(0, 8))
    scrollbar.pack(side="right", fill="y", padx=(0, 10), pady=(0, 8))


def parse_keywords(text: str) -> list:
    return [k.strip() for k in re.split(r'[,，\s]+', text) if k.strip()] or ["默认关键词"]


def safe_int(val: str) -> int | None:
    return int(val) if val and val.isdigit() else None


def safe_float(val: str) -> float | None:
    if not val:
        return None
    try:
        return float(val)
    except ValueError:
        return None


def parse_exclude_brands(text: str) -> set:
    if not text:
        return set()
    return {b.strip().lower() for b in re.split(r'[,，\s]+', text) if b.strip()}